package cn.kgc.vue.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.kgc.vue.common.ResponseResult;
import cn.kgc.vue.common.ResponseStatus;
import cn.kgc.vue.dto.UserPageDTO;
import cn.kgc.vue.entity.*;
import cn.kgc.vue.form.AddUserForm;
import cn.kgc.vue.form.UserLoginForm;
import cn.kgc.vue.mapper.*;
import cn.kgc.vue.service.UserService;
import cn.kgc.vue.utils.JWTUtil;
import cn.kgc.vue.utils.SaltUtil;
import cn.kgc.vue.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RolePersMapper rolePersMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public ResponseResult login(UserLoginForm userLoginForm) {
        ResponseResult responseResult = new ResponseResult();
        // 1.判定验证码
        String code = userLoginForm.getCode();
        String imguuid = userLoginForm.getImguuid();
        // 根据uuid 获取redis中缓存的验证码
        String captcha = stringRedisTemplate.opsForValue().get(imguuid);

        //比较  captcha 时效性   code
        if(StringUtils.isEmpty(captcha)){
            responseResult.fail(ResponseStatus.CODE_EXPIRE);
            return responseResult;
        }

        if (!StringUtils.equals(code,captcha)){
            responseResult.fail(ResponseStatus.CODE_ERROR);
            return responseResult;
        }

        // 2.验证码判定通过   更具用户名查询用户信息
        String username = userLoginForm.getUsername();
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername,username);
        User user = userMapper.selectOne(lambda);
        // 判定用户是否存在
        if(ObjectUtil.isEmpty(user)){
            throw  new UnknownAccountException("用户名不存在");
        }

        // 判定密码是否正确
        String salt = user.getSalt();
        String md5Pwd = new Md5Hash(userLoginForm.getPassword(), salt, 1024).toHex();
        String password = user.getPassword();
        if(!StringUtils.equals(md5Pwd,password)){
            throw  new IncorrectCredentialsException("密码错误");
        }

        //判定用户状态  是否可用  state  1 正常    0 禁用
        Integer state = user.getState();
        if(state==0){
            throw new LockedAccountException("账户被禁用");
        }
        // 3.登录成功  生成token  返回前端
        // token的载荷
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("username",user.getUsername());
        claims.put("userId",user.getId());
        String token = JWTUtil.createToken(claims);

        // 需要返回到前端的数据
        HashMap<String, Object> data = new HashMap<>();
        data.put("token",token);
        data.put("nickName",user.getNickName());
        responseResult.success(ResponseStatus.LOGIN_SUCCESS,data);
        return responseResult;
    }

    @Override
    public ResponseResult getUserPage(UserPageDTO userPageDTO) {
        // 1.用户表的分页查询    搜索
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(StringUtils.isNotBlank(userPageDTO.getUsername()),User::getUsername,userPageDTO.getUsername())
                .eq(ObjectUtil.isNotEmpty(userPageDTO.getState()),User::getState,userPageDTO.getState())
                 .orderByDesc(User::getId);

        Page<User> userPage = new Page<>(userPageDTO.getCurrentPage(), userPageDTO.getLimit());
        userMapper.selectPage(userPage, lambda);

        // 获取用户的分页数据
        List<User> users = userPage.getRecords();
        long total = userPage.getTotal();

        //遍历用户分页数据 封装成前端页面需要的数据形式
        List<UserVO> userVOS = users.stream().map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user,userVO);

            // 部门名称   dept  dept_id
            Integer deptId = user.getDeptId();
            Dept dept = deptMapper.selectById(deptId);
            userVO.setDeptName(dept.getDeptName());
            // 角色名称列表  userId  -> user_role  ->rIds  ->role ->roleName
            Integer userId = user.getId();
            QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
            userRoleQueryWrapper.eq("user_id",userId);
            List<Integer> rIds = userRoleMapper.selectList(userRoleQueryWrapper).stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
            List<String> roleNames = roleMapper.selectBatchIds(rIds).stream().map(r -> r.getRoleCh()).collect(Collectors.toList());
            userVO.setRoleNames(roleNames);

            return userVO;
        }).collect(Collectors.toList());

        HashMap<String, Object> result = new HashMap<>();
        result.put("total",total);
        result.put("pageData",userVOS);

        ResponseResult responseResult = new ResponseResult();
        responseResult.success(ResponseStatus.SUCCESS,result);
        return responseResult;
    }

    @Override
    public ResponseResult removeBatch(List<Integer> uIds) {

        ResponseResult responseResult = new ResponseResult();
        // 根据用户id 删除用户信息
        userMapper.deleteBatchIds(uIds);
        //根据用户id  删除用户角色关联表中的数据
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.in(UserRole::getUserId,uIds);
        userRoleMapper.delete(lambda);
        responseResult.success();
        return responseResult;
    }

    //更新用户
    @Override
    public ResponseResult updateUser(AddUserForm addUserForm) {
        ResponseResult responseResult = new ResponseResult();
        //获取用户信息
        User user = new User();
        BeanUtils.copyProperties(addUserForm,user);
        userMapper.updateById(user);

        //  获取用户角色列表
        List<Integer> roleIds = addUserForm.getRoleIds();
        // 根据用户的id  删除user_role
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,user.getId());
        userRoleMapper.delete(lambda);
        //添加的新的角色  user_role
        roleIds.forEach(rId->{
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(rId);
            userRoleMapper.insert(userRole);
        });
        responseResult.success();
        return responseResult;
    }

    //添加用户
    @Override
    public ResponseResult addUser(AddUserForm addUserForm) {
        ResponseResult responseResult = new ResponseResult();
        //  添加用户 需要设置默认密码 加密 加盐
        String salt = SaltUtil.getSalt(8);
        addUserForm.setSalt(salt);
        String md5Pwd = new Md5Hash("888888", salt, 1024).toHex();
        addUserForm.setPassword(md5Pwd);

        User user = new User();
        BeanUtils.copyProperties(addUserForm,user);

        // 判定用户是否已经存在
        String username = user.getUsername();
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername,username);
        User usr = userMapper.selectOne(lambda);
        if (ObjectUtil.isNotNull(usr)){
            responseResult.fail(ResponseStatus.USER_EXIST);
            return  responseResult;
        }

        userMapper.insert(user);
        // 获取自增主键
        Integer userId = user.getId();
        // 角色列表   user_role
        List<Integer> roleIds = addUserForm.getRoleIds();
        roleIds.forEach(rId->{
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(rId);
            userRoleMapper.insert(userRole);
        });
        responseResult.success();
        return responseResult;
    }

    @Override
    public ResponseResult getUserById(Integer id) {

        // 用户表信息
        ResponseResult responseResult = new ResponseResult();
        User user = userMapper.selectById(id);

        // 用户角色id
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id",id);
        List<Integer> rIds = userRoleMapper.selectList(userRoleQueryWrapper).stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user,userVO);
        userVO.setRoleIds(rIds);

        responseResult.success(ResponseStatus.SUCCESS,userVO);

        return  responseResult;
    }

    @Override
    public ResponseResult getMenu(HttpServletRequest request) {

        ResponseResult responseResult = new ResponseResult();
        //通过token解析用户信息  uid
        String token = request.getHeader("token");
        Integer uid = (Integer) JWTUtil.getClaim(token).get("userId");

        //根据用户id  查询用户角色列表  user_role
        QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id",uid);
        List<Integer> rids = userRoleMapper.selectList(userRoleQueryWrapper).stream().map(ur -> ur.getRoleId()).collect(Collectors.toList());
        // 根据角色id 查询角色权限关联表  permissionId
        QueryWrapper<RolePers> rolePersQueryWrapper = new QueryWrapper<>();
        rolePersQueryWrapper.in("role_id",rids);
        Set<Integer> pids = rolePersMapper.selectList(rolePersQueryWrapper).stream().map(rp -> rp.getPerId()).collect(Collectors.toSet());

        // 判定角色是否有权限
        if(pids.size()==0){
            //int[] pids = {};
            responseResult.success(ResponseStatus.SUCCESS,new ArrayList<>());
            return responseResult;
        }

        // 根据权限id  查询权限表  获取权限详细信息  排除按钮级别权限
        LambdaQueryWrapper<Permission> lambda = new QueryWrapper<Permission>().lambda();
        lambda.in(Permission::getId,pids)
                .ne(Permission::getIsMenu,2);

        List<Permission> permissions = permissionMapper.selectList(lambda);
        responseResult.success(ResponseStatus.SUCCESS,permissions);
        return responseResult;
    }


}




